﻿using System;
using System.Collections.Generic;
using System.Linq;
using WorldBankBBS.Data;
using WorldBankBBS.Input;
using WorldBankBBS.Pathing;
using WorldBankBBS.Resources;
using WorldBankBBS.RichEditor;
using WorldBankBBS.Translators;
using Session = WorldBankBBS.Logic.Session;

namespace WorldBankBBS.Handlers
{
    public class PostLoginHandler : IPathHandler
    {
        private Session _session = null;
        private event TextInputHandler TextInput;
        public PostLoginHandler(Session session)
        {
            _session = session;
        }

        public static event EventHandler<Session> PostLoginFileHandler;

        public static void OnPostLogin(object sender, Session session)
        {
            if (PostLoginFileHandler != null)
            {
                PostLoginFileHandler(sender, session);
            }

            new PostLoginHandler(session).DisplayNews();
        }

        internal void DisplayNews()
        {
            using (var mh = new ModelHelper())
            {
                mh.BeginNewContext();

                var news =
                    mh.Context.News.Where(
                        n =>
                            !n.IsDeleted &&
                            n.NewsUsers.FirstOrDefault(nu => nu.UserUID == _session.User.UserUID) == null)
                        .OrderBy(x => x.Timestamp)
                        .ToList();

                if (news != null && news.Count > 0)
                {
                    foreach (var newsItem in news)
                    {
                        ReadNews(newsItem, true, mh);

                        _session.InvokePause(_session.Encoding);

                    }
                }
                else
                {
                    var translator = _session.Encoding.GetTranslator(_session);
                    var buffer = new byte[1024];
                    var l = 0;

                    l = translator.StringToBytes(buffer, StringTable.NEWS_NONE);
                    _session.Connection.SendData(buffer, 0, l);
                }

                var user = mh.Context.Users.FirstOrDefault(x => x.UserUID == _session.User.UserUID);

                if (user != null && user.UserSecurity != null)
                {
                    if (user.UserSecurity.IsNewsAdmin)
                    {
                        AdminNews(user, mh);
                    }
                }
            }
        }

        private void AdminNews(User user, ModelHelper mh)
        {
            var translator = _session.Encoding.GetTranslator(_session);
            var buffer = new byte[1024];
            var l = 0;

            var option = " ";

            while (option != string.Empty)
            {
                l = translator.StringToBytes(buffer, StringTable.NEWS_PROMPT);

                _session.Connection.SendData(buffer, 0, l);

                var newsItems = ListNews(user, mh, false);
                InputHandler inputHandler = new InputHandler();
                TextInput -= inputHandler.OnTextInput;
                TextInput += inputHandler.OnTextInput;

                option = TextInput(_session, translator, _session.Connection, 6, false);

                TextInput -= inputHandler.OnTextInput;

                if (!string.IsNullOrEmpty(option))
                {
                    int itemNumber = 0;
                    if (Int32.TryParse(option, out itemNumber) && itemNumber >0 && itemNumber <= newsItems.Count)
                    {
                        ReadNews(newsItems[itemNumber - 1], false, mh);
                    }
                    else
                    {
                        switch (option.ToLower()[0])
                        {
                            case 'n':
                                AddNews(user, mh);
                                break;

                            case 'l':
                                ListNews(user, mh, true);
                                break;

                            case 'd':
                                if (Int32.TryParse(option.Substring(1), out itemNumber))
                                {
                                    DeleteNews(newsItems[itemNumber - 1], mh);
                                }
                                break;
                        }
                    }
                }
            }
        }

        private void DeleteNews(News newsItem, ModelHelper mh)
        {
            newsItem.IsDeleted = true;
            mh.Context.SaveChanges();
        }

        private void AddNews(User user, ModelHelper mh)
        {
            var translator = _session.Encoding.GetTranslator(_session);
            var buffer = new byte[1024];
            var l = 0;

            l = translator.StringToBytes(buffer, StringTable.NEWS_NEW_SUBJECT);
            _session.Connection.SendData(buffer, 0, l);

            InputHandler inputHandler = new InputHandler();
            TextInput -= inputHandler.OnTextInput;
            TextInput += inputHandler.OnTextInput;

            var option = TextInput(_session, translator, _session.Connection, 30, false);

            TextInput -= inputHandler.OnTextInput;

            if (option.Trim() != string.Empty)
            {
                var te = new TextEditor();

                if (te.Initialize(_session,
                            new TextEditor.Field<string>(0, 0)
                            {
                                Format = "0:-" + ((int)_session["ScreenWidth"] - 10),
                                LabelText = string.Empty,
                                Value = string.Empty
                            },
                            new TextEditor.Field<DateTime>(0, 0)
                            {
                                Format = "0:-1",
                                LabelText = string.Empty,
                                Value = DateTime.UtcNow
                            },
                            new TextEditor.Field<string>(0, 0)
                            {
                                Format = "0:-" + ((int)_session["ScreenWidth"] - 10),
                                LabelText = string.Empty,
                                Value = string.Empty
                            },
                            new TextEditor.Field<string>(0, 0)
                            {
                                Format = "0:-" + ((int)_session["ScreenWidth"] - 10),
                                LabelText = "{PURPLE}Subject{WHITE}:",
                                Value = option
                            },
                            1, 1,
                            new TextEditor.Field<string>(0, (int)_session["ScreenHeight"] - 1)
                            {
                                Format = "0:-" + ((int)_session["ScreenHeight"] - 1),
                                LabelText = _session.Encoding == "PETSCII" ? "{WHITE}. on blank line for command menu" : "{WHITE}^{YELLOW}A {WHITE}- {CYAN}Abort{WHITE}, ^{YELLOW}S {WHITE}- {CYAN}Save{WHITE}, ^{YELLOW}Z {WHITE}- {CYAN}Undo{WHITE}, ^{YELLOW}R {WHITE}- {CYAN}Redraw{WHITE}",
                                Value = string.Empty
                            }
                    
                    ))
                {
                    l = translator.StringToBytes(buffer, StringTable.NEWS_POSTED);
                    _session.Connection.SendData(buffer, 0, l, l);

                    var news = new News
                    {
                        NewsUID = Guid.NewGuid(),
                        Timestamp = DateTime.UtcNow,
                        NewsMessage = te.Text,
                        NewsSubject = option,
                    };

                    mh.Context.News.Add(news);

                    mh.Context.SaveChanges();
                }
            }
            else
            {
                l = translator.StringToBytes(buffer, StringTable.NEWS_ABORTED);
                _session.Connection.SendData(buffer, 0, l, l);
            }
        }
    

        private void ReadNews(News newsItem, bool markRead, ModelHelper mh)
        {
            var translator = _session.Encoding.GetTranslator(_session);
            var buffer = new byte[1024];
            var l = 0;

            l = translator.StringToBytes(buffer, StringTable.NEWS_BANNER, newsItem.Timestamp.ToLocalTime().ToShortDateString(),
                newsItem.NewsSubject, newsItem.NewsMessage);
            var tbuffer = buffer.WrapText(0, l, _session.Encoding, (int)_session["ScreenWidth"]);
            _session.Connection.SendData(tbuffer, 0, tbuffer.Length);

            if (markRead)
            {
                var nu = new NewsUser
                {
                    NewsUID = newsItem.NewsUID,
                    UserUID = _session.User.UserUID,
                    DateRead = DateTime.UtcNow,
                };

                mh.Context.NewsUsers.Add(nu);

                mh.Context.SaveChanges();
            }
        }

        private List<News> ListNews(User user, ModelHelper mh, bool display)
        {
            var result = new List<News>();

            if (mh != null && mh.Context != null)
            {
                result = mh.Context.News.Where(n => !n.IsDeleted).OrderBy(n => n.Timestamp).ToList();

                if (display)
                {
                    var builder = new List<byte>();
                    var translator = _session.Encoding.GetTranslator(_session);
                    var buffer = new byte[1024];
                    var l = 0;

                    l = translator.StringToBytes(buffer, StringTable.NEWS_NEW_TOP);
                    for (int i = 0; i < l; ++i)
                    {
                        builder.Add(buffer[i]);
                    }

                    var count = 1;
                    foreach (var newsItem in result)
                    {
                        l = translator.StringToBytes(buffer, StringTable.NEWS_ITEM, count++,
                            newsItem.Timestamp.ToLocalTime().ToShortDateString(),
                            newsItem.NewsSubject);

                        for (int i = 0; i < l; ++i)
                        {
                            builder.Add(buffer[i]);
                        }
                    }

                    _session.Connection.SendData(builder.ToArray());
                }
            }

            return result;
        }

        public Session Session
        {
            get { return _session; }
        }

        public void ProcessPath(string path)
        {
            switch (path)
            {
                case "DisplayNews": DisplayNews();
                    break;
            }
        }
    }
}
